package ms.pay.smallpro;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * Project Name: ms
 * File Name: WechatPay
 * Package Name: ms.pay.smallpro
 * Date: 2018/5/11  11:45
 * Copyright (c) 2018, tianyul All Rights Reserved.
 * 微信小程序支付
 */
public class WechatPay {

    /**
     * 获取小程序前端所需要的4个参数
     * @param wechatPayParam
     * @return
     */
    public Map<String,Object> getPaySign(WechatPayParam wechatPayParam) {
        Map<String,Object> result = new HashMap<>();

        String fee = new BigDecimal(wechatPayParam.getFee()).multiply(new BigDecimal("100")).intValue() + "";

        //生成的随机字符串
        String nonce_str = getRandomStringByLength(32);

        //组装参数，用户生成统一下单接口的签名
        Map<String, String> packageParams = new HashMap<String, String>();
        packageParams.put("appid", wechatPayParam.getAppId());
        packageParams.put("mch_id", wechatPayParam.getMchId());
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", wechatPayParam.getBody());//商品名称
        packageParams.put("out_trade_no", wechatPayParam.getOrderId());//商户订单号
        packageParams.put("total_fee", fee);//支付金额，这边需要转成字符串类型，否则后面的签名会失败  ObjectTranslate.getString(order.get("transport"))
        packageParams.put("spbill_create_ip", "127.0.0.1");
        packageParams.put("notify_url", wechatPayParam.getNotifyUrl());//支付成功后的回调地址
        packageParams.put("trade_type", "JSAPI");//支付方式
        packageParams.put("openid", wechatPayParam.getOpenId());

        String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

        //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
        String mysign = PayUtil.sign(prestr, wechatPayParam.getKey(), "utf-8").toUpperCase();

        //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
        String xml = "<xml>" + "<appid>" + wechatPayParam.getAppId() + "</appid>"
                + "<body><![CDATA[" + wechatPayParam.getBody() + "]]></body>"
                + "<mch_id>" + wechatPayParam.getMchId() + "</mch_id>"
                + "<nonce_str>" + nonce_str + "</nonce_str>"
                + "<notify_url>" + wechatPayParam.getNotifyUrl() + "</notify_url>"
                + "<openid>" + wechatPayParam.getOpenId() + "</openid>"
                + "<out_trade_no>" + wechatPayParam.getOrderId() + "</out_trade_no>"
                + "<spbill_create_ip>" + "127.0.0.1" + "</spbill_create_ip>"
                + "<total_fee>" + fee + "</total_fee>"
                + "<trade_type>" + "JSAPI" + "</trade_type>"
                + "<sign>" + mysign + "</sign>"
                + "</xml>";

//        System.out.println("调试模式_统一下单接口 请求XML数据：" + xml);

        //调用统一下单接口，并接受返回的结果
        String res = PayUtil.httpRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", xml);

//        System.out.println("调试模式_统一下单接口 返回XML数据：" + res);

        // 将解析结果存储在HashMap中
        Map map;
        try {
            map = PayUtil.doXMLParse(res);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("error", "pay_fail");
            return result;
        }

        String return_code = (String) map.get("return_code");//返回状态码

        if(return_code=="SUCCESS"||return_code.equals(return_code)){
            String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
            result.put("nonceStr", nonce_str);
            result.put("package", "prepay_id=" + prepay_id);
            Long timeStamp = System.currentTimeMillis() / 1000;
            result.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
            //拼接签名需要的参数
            String stringSignTemp = "appId=" + wechatPayParam.getAppId() + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
            //再次签名，这个签名用于小程序端调用wx.requesetPayment方法
            String paySign = PayUtil.sign(stringSignTemp, wechatPayParam.getKey(), "utf-8").toUpperCase();
            result.put("nonce_str", nonce_str);
            result.put("package", "prepay_id=" + prepay_id);
            result.put("timeStamp", timeStamp + "");
            result.put("paySign", paySign);
        }

        return result;
    }

    /**
     *
     * @param request 请求request
     * @param key  key
     * @return
     * @throws Exception
     */
    private Map<String,Object> checkNotifyXml(HttpServletRequest request, String key) throws Exception {
        Map<String,Object> result = new HashMap<>();

        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        // sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        System.out.println("接收到的报文：" + notityXml);

        Map map = PayUtil.doXMLParse(notityXml);

        String return_code = map.get("return_code").toString().toUpperCase();

        if(return_code.equals("SUCCESS")){
            //进行签名验证，看是否是从微信发送过来的，防止资金被盗
            // 验证签名是否正确
            if (PayUtil.checkSign(notityXml, key)) {
                // 订单支付成功 业务处理
                String out_trade_no = ObjectTranslate.getString(map.get("out_trade_no")); // 商户订单号
                // 逻辑代码
                result.put("orderId", out_trade_no);
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        result.put("resXml", resXml);
//        //由controller 返回给微信
//        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
//        out.write(resXml.getBytes());
//        out.flush();
//        out.close();

        return result;
    }


    /**
     * 生成随机数
     * @param length
     * @return
     */
    private String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}
